#include "U2MemoryTracker.h"

#include "U2StringUtil.h"



#if U2_PLATFORM == U2_PLATFORM_WIN32
#   include <windows.h>
#	define U2_OutputCString(str)        ::OutputDebugStringA(str)
#	define U2_OutputWString(str)        ::OutputDebugStringW(str)
#else
#	define U2_OutputCString(str)        std::cerr << str
#	define U2_OutputWString(str)        std::cerr << str
#endif



U2EG_NAMESPACE_USING

//--------------------------------------------------------------------------
U2MemoryTracker& U2MemoryTracker::getSingleton()
{
	static U2MemoryTracker tracker;
	return tracker;
}
//--------------------------------------------------------------------------
void U2MemoryTracker::_recordAlloc(void* ptr, size_t sz, unsigned int pool, 
								 const char* file, size_t ln, const char* func)
{
	U2_LOCK_AUTO_MUTEX

	assert(m_allocations.find(ptr) == m_allocations.end() && "Double allocation with same address - "
		"this probably means you have a mismatched allocation / deallocation style, "
		"check if you're are using OGRE_ALLOC_T / OGRE_FREE and OGRE_NEW_T / OGRE_DELETE_T consistently");

	m_allocations[ptr] = Alloc(sz, pool, file, ln, func);
	if(pool >= m_allocationsByPool.size())
		m_allocationsByPool.resize(pool+1, 0);
	m_allocationsByPool[pool] += sz;
	m_zTotalAllocations += sz;
}
//--------------------------------------------------------------------------
void U2MemoryTracker::_recordDealloc(void* ptr)
{
	// deal cleanly with null pointers
	if (!ptr)
		return;

	U2_LOCK_AUTO_MUTEX

	AllocationMap::iterator i = m_allocations.find(ptr);
	assert(i != m_allocations.end() && "Unable to locate allocation unit - "
		"this probably means you have a mismatched allocation / deallocation style, "
		"check if you're are using OGRE_ALLOC_T / OGRE_FREE and OGRE_NEW_T / OGRE_DELETE_T consistently");
	// update category stats
	m_allocationsByPool[i->second.pool] -= i->second.bytes;
	// global stats
	m_zTotalAllocations -= i->second.bytes;
	m_allocations.erase(i);
}	
//--------------------------------------------------------------------------
size_t U2MemoryTracker::getTotalMemoryAllocated() const
{
	return m_zTotalAllocations;
}
//--------------------------------------------------------------------------
size_t U2MemoryTracker::getMemoryAllocatedForPool(unsigned int pool) const
{
	return m_allocationsByPool[pool];
}
//--------------------------------------------------------------------------
void U2MemoryTracker::reportLeaks()
{
	U2StringUtil::U2StrStreamType os;

	if (m_allocations.empty())
		os << "No leaks!";
	else
	{
		size_t totalMem = 0;
		os << "Leaks detected:" << std::endl << std::endl;
		for (AllocationMap::const_iterator i = m_allocations.begin(); i != m_allocations.end(); ++i)
		{
			const Alloc& alloc = i->second;
			if (!alloc.filename.empty())
				os << alloc.filename << "(" << alloc.line << ", " << alloc.function << "): ";
			else
				os << "(unknown source): ";
			os << alloc.bytes << " bytes";
			os << std::endl;
			totalMem += alloc.bytes;
		}

		os << std::endl;
		os << m_allocations.size() << " leaks detected, " << totalMem << " bytes total";
	}

	if (m_bDumpToStdOut)
		std::cout << os.str();

	std::ofstream of;
	of.open(m_szLeakFileName.c_str());
	of << os.str();
	of.close();

    U2_OutputCString(os.str().c_str());
}
